﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;

namespace CRM.UTIL
{
    public class RunAliAPI
    {
        private static string strAppKey = string.Empty;
        private static string strAccToken = string.Empty;
        private static string strAppSecret = string.Empty;
        public static string strHui = string.Empty;

        public static string GetRemoteHtmlCodeByEncoding(string Url, string encode)
        {
            HttpWebResponse Result = null;

            try
            {
                HttpWebRequest Req = (HttpWebRequest)System.Net.WebRequest.Create(Url);
                Req.Method = "get";
                Req.ContentType = "application/x-www-form-urlencoded";
                Req.Credentials = CredentialCache.DefaultCredentials;
                Result = (HttpWebResponse)Req.GetResponse();

                StreamReader ReceiveStream = new StreamReader(Result.GetResponseStream(), Encoding.GetEncoding(encode));
                string OutPutString;
                try
                {
                    OutPutString = ReceiveStream.ReadToEnd();
                }
                catch
                {
                    OutPutString = string.Empty;
                }
                finally
                {
                    ReceiveStream.Close();
                }

                return OutPutString;
            }
            catch
            {
                return string.Empty;
            }
            finally
            {
                if (Result != null)
                {
                    Result.Close();
                }
            }
        }  
        public RunAliAPI()
        {
            var aliData=new Hashtable();
            try
            {
                aliData =
                    (Hashtable)
                        JSON.Decode(FileHelper.Read(HttpContext.Current.Server.MapPath("/Static/AliFile/alikey.txt")));
            }
            catch (Exception ex)
            {
                aliData = aliData =
                    (Hashtable)
                        JSON.Decode(GetRemoteHtmlCodeByEncoding(ConfigurationManager.AppSettings["SiteRoot"].TrimEnd('/') +
                                            "/Static/AliFile/alikey.txt","UTF-8"));
            }

            strAppKey = aliData["appKey"].ToString();
            strAccToken = aliData["access_token"].ToString();
            strAppSecret = aliData["appSecret"].ToString();
            string strTokeyTime = aliData["access_token_time"].ToString();
            string strRefresh_token = aliData["refresh_token"].ToString();
            string strTimeout = aliData["refresh_token_timeout"].ToString();
            string strCode = aliData["code"].ToString();

            if (string.IsNullOrEmpty(strCode))
            {
                //去登录界面获得授权
                var cslist = new Dictionary<string, string>
                {
                    {"client_id", strAppKey},
                    {"site", "aliexpress"},
                    {"redirect_uri", ConfigurationManager.AppSettings["SiteRoot"].TrimEnd('/') + "/SaveAliCode.aspx"},
                    {"state", "deng"}
                };
                cslist.Add("_aop_signature", CodeSign(cslist, strAppSecret));

                string url = GetCodeUrl(cslist);
                HttpContext.Current.Response.Redirect(url);
            }
            else
            {
                ///比较刷新令牌到期小于30天，更新刷新令牌
                /// 20160312012014000-0800
                //2016 03 12 01 20 14 000-0800 
                string guoqi = strTimeout.Substring(0, 4) + "-" 
                    + strTimeout.Substring(4, 2) + "-" 
                    + strTimeout.Substring(6, 2) + " " 
                    + strTimeout.Substring(8, 2) + ":" 
                    + strTimeout.Substring(10, 2) + ":" 
                    + strTimeout.Substring(12, 2);
                DateTime refreshTime = Convert.ToDateTime(guoqi);

                TimeSpan reTS = refreshTime.Subtract(DateTime.Now);

                if (reTS.Days < 25)  //间隔日期小于25天了需要重新取得refrentekon
                {
                    strHui = "需要刷新refreshtoken了";
                    //换取refreshToken的url示例如下：
                   // 请求参数如下：client_id=YOUR_APPKEY&client_secret=YOUR_APPSECRET&refresh_token=REFRESH_TOKEN&access_token=ACCESS_TOKEN
                    //返回结果类似getToken的返回结果
                    string refreshURL = ConfigurationManager.AppSettings["RefreshURL"] + strAppKey;
                    var refreshLs = new Dictionary<string, string>();
                    refreshLs.Add("client_id", strAppKey);
                    refreshLs.Add("client_secret", strAppSecret);
                    refreshLs.Add("refresh_token", strRefresh_token);
                    refreshLs.Add("access_token", strAccToken);
                    //string url = refreshURL + "?client_id=" + strAppKey + "&client_secret=" + strAppSecret + "&refresh_token=" + strRefresh_token + "&access_token=" + strAccToken;

                    var refreshWU = new WebUtils();
                    string refreshText = refreshWU.DoGet(refreshURL, refreshLs);
                    Hashtable hs = (Hashtable)JSON.Decode(refreshText);
                    //保存令牌 
                    aliData["aliId"] = hs["aliId"];
                    aliData["refresh_token"] = hs["refresh_token"];
                    aliData["access_token"] = hs["access_token"];
                    aliData["access_token_time"] = DateTime.Now.ToString(CultureInfo.InvariantCulture);
                    aliData["refresh_token_timeout"] = hs["refresh_token_timeout"];
                    FileHelper.Write(HttpContext.Current.Server.MapPath("/Static/AliFile/alikey.txt"), JSON.Encode(aliData));
                    strHui = JSON.Encode(aliData);
                    //strHui = "需要重新刷新";
                }
                else
                {
                    //strHui = "不需要刷新refreshtoken了";
                    ////比较令牌保存时间，如果比现在早10个小时以上就更新
                    DateTime tokeyTime = Convert.ToDateTime(strTokeyTime);
                    TimeSpan tokeyTs = DateTime.Now.Subtract(tokeyTime);

                    if ((tokeyTs.Hours > 8) || (tokeyTs.Days >= 1))
                    {
                        //strHui = "需要重新取令牌";
                        //https://gw.api.alibaba.com/openapi/param2/1/system.oauth2/getToken/YOUR_APPKEY
                        //grant_type=refresh_token&client_id=YOUR_APPKEY&client_secret=YOUR_APPSECRET&refresh_token=REFRESH_TOKEN
                        string urlStr =
                            ConfigurationManager.AppSettings["GetTokenWithRefreshToken"] + strAppKey;

                        Dictionary<string, string> dc = new Dictionary<string, string>();
                        dc.Add("grant_type", "refresh_token");
                        dc.Add("client_id", strAppKey);
                        dc.Add("client_secret", strAppSecret);
                        dc.Add("refresh_token", strRefresh_token);

                        WebUtils wu = new WebUtils();
                        string tbxToken = wu.DoPost(urlStr, dc);
                        Hashtable hs = (Hashtable)JSON.Decode(tbxToken);
                        //保存令牌 
                        aliData["aliId"] = hs["aliId"];
                        aliData["access_token"] = hs["access_token"];
                        aliData["access_token_time"] = DateTime.Now.ToString(CultureInfo.InvariantCulture);
                        try
                        {
                            FileHelper.Write(HttpContext.Current.Server.MapPath("/Static/AliFile/alikey.txt"),
                                JSON.Encode(aliData));
                        }
                        catch (Exception ex)
                        {
                            
                        }
                        strAccToken = hs["access_token"].ToString();
                        // strHui = tbxToken;
                    }
                    else
                    {
                        strHui = "不需要重新取令牌";
                    }
                    //strHui = tokeyTs.Days.ToString();
                    
                }
            }
        }


        //public string GetAliData(Dictionary<string, string> paramDic)
        //{
        //    return GoRun("http://gw.api.alibaba.com:80/openapi",
        //            "param2/1/aliexpress.open/api.queryWarrantiesByOrderId/4957740", paramDic, false,
        //            false);
        //}
        
        /// <summary>
        /// 根据订单号获取订单信息
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="hasAppKey"></param>
        /// <param name="hasToken"></param>
        /// <returns></returns>
        public string GetOrderInfo(string orderId,bool hasAppKey=true,bool hasToken=true)
        {
            var dl = new Dictionary<string, string>
            {
                {"orderId", orderId},
                {"supplierId", ConfigurationManager.AppSettings["SupplierId"]}
            };

            return GoRun("http://gw.api.alibaba.com:80/openapi",
                "param2/1/aliexpress.open/api.queryWarrantiesByOrderId/4957740", dl, hasAppKey, hasToken);
        }

        public string GetOrderList(string startBuyTime,string endBuyTime,int pageSize,int pageIndex,bool hasAppKey = true, bool hasToken = true)
        {
            //http://gw.api.alibaba.com:80/openapi/param2/1/aliexpress.open/alibaba.ae.warrantie.getList/4957740?supplierId=wisetech&startBuyTime=2016-01-01%2000%3A00%3A00&endBuyTime=2016-04-01%2000%3A00%3A00&pageSize=200&pageNo=1&_aop_signature=923FF315C4E93FD37ECD21FFC484F00546BCFB5B
            var dl=new Dictionary<string, string>
            {
                {"supplierId", ConfigurationManager.AppSettings["SupplierId"]},
                {"startBuyTime", startBuyTime},
                {"endBuyTime", endBuyTime},
                {"pageSize", pageSize.ToString(CultureInfo.InvariantCulture)},
                {"pageNo", pageIndex.ToString(CultureInfo.InvariantCulture)}
            };
            return GoRun("http://gw.api.alibaba.com:80/openapi",
                "param2/1/aliexpress.open/alibaba.ae.warrantie.getList/4957740", dl, hasAppKey, hasToken);
        }

        /// <summary>
        /// 获取生效订单
        /// </summary>
        /// <param name="startDate">2016-01-01 00:00:00</param>
        /// <param name="endDate">2016-01-01 00:00:00</param>
        /// <param name="pageSize"></param>
        /// <param name="pageIndex"></param>
        /// <param name="hasAppKey"></param>
        /// <param name="hasToken"></param>
        /// <returns></returns>
        public string GetEffOrder(string startDate, string endDate,int pageSize,int pageIndex, bool hasAppKey = true, bool hasToken = true)
        {
            var dl = new Dictionary<string, string>
            {
                {"supplierId", ConfigurationManager.AppSettings["SupplierId"]},
                {"startTime", startDate},
                {"endTime", endDate},
                {"pageSize", pageSize.ToString(CultureInfo.InvariantCulture)},
                {"pageNo", pageIndex.ToString(CultureInfo.InvariantCulture)}
            };
            return GoRun("http://gw.api.alibaba.com:80/openapi",
                "param2/1/aliexpress.open/api.queryWarrantiesInforce/4957740", dl, hasAppKey, hasToken);
        }

        private string GoRun(string site,string urlPath,Dictionary<string, string> paramDic,bool hasAppKey=true,bool hasToken=true)
        {
            if (hasAppKey)
                urlPath = urlPath.TrimEnd('/') + "/" + strAppKey;
            if(hasToken)
                paramDic.Add("access_token", strAccToken);
            //签名
            var signa = ApiSign(urlPath, paramDic);

            var debugSinature = ConfigurationManager.AppSettings["DebugSignature"];

            paramDic.Add("_aop_signature", string.IsNullOrEmpty(debugSinature) ? signa : debugSinature);

            return new WebUtils().DoGet(site.TrimEnd('/') + "/" + urlPath.TrimStart('/'), paramDic);

        }


        /// <summary>
        /// 签名参数生成工具类
        /// </summary>
        /// <param name="urlPath">基础url部分</param>
        /// <param name="paramDic">paramDic: 请求参数，即queryString + request body 中的所有参数</param>
        /// <param name="appSecret"></param>
        /// <returns></returns>
        private static string ApiSign(string urlPath, Dictionary<string, string> paramDic, string appSecret)
        {
            byte[] signatureKey = Encoding.UTF8.GetBytes(appSecret);//此处用自己的签名密钥
            var list = new List<string>();
            foreach (KeyValuePair<string, string> kv in paramDic)
            {
                list.Add(kv.Key + kv.Value);
            }
            list.Sort();
            string tmp = urlPath;
            foreach (string kvstr in list)
            {
                tmp = tmp + kvstr;
            }
            //HMAC-SHA1
            var hmacsha1 = new HMACSHA1(signatureKey);
            hmacsha1.ComputeHash(Encoding.UTF8.GetBytes(tmp));
            /*
            hmacsha1.ComputeHash(Encoding.UTF8.GetBytes(urlPath));
            foreach (string kvstr in list)
            {
                hmacsha1.ComputeHash(Encoding.UTF8.GetBytes(kvstr));
            }
             */
            byte[] hash = hmacsha1.Hash;
            //TO HEX
            return BitConverter.ToString(hash).Replace("-", string.Empty).ToUpper();
        }

        private static string ApiSign(string urlPath, Dictionary<string, string> paramDic)
        {
            return ApiSign(urlPath, paramDic, strAppSecret);
        }

        private static string CodeSign(Dictionary<string, string> paramDic, string appSecret)
        {
            //此处用自己的签名密钥
            byte[] signatureKey = Encoding.UTF8.GetBytes(appSecret);
            //第一步：拼装key+value
            var list = paramDic.Select(kv => kv.Key + kv.Value).ToList();
            //第二步：排序
            list.Sort();
            //第三步：拼装排序后的各个字符串
            var tmp = list.Aggregate(string.Empty, (current, kvstr) => current + kvstr);
            //第四步：将拼装后的字符串和app密钥一起计算签名
            //HMAC-SHA1
            var hmacsha1 = new HMACSHA1(signatureKey);
            hmacsha1.ComputeHash(Encoding.UTF8.GetBytes(tmp));
            byte[] hash = hmacsha1.Hash;
            //TO HEX
            return BitConverter.ToString(hash).Replace("-", string.Empty).ToUpper();
        }

        private static string GetCodeUrl(Dictionary<string, string> paramDic)
        {
            var retStr = paramDic.Aggregate(string.Empty, (current, kv) => current + (kv.Key + "=" + kv.Value + "&"));
            return ConfigurationManager.AppSettings["AliAuthPage"] + retStr.Substring(0, retStr.Length - 1);
        }
    }
}
